package com.shine.app.commons;

import android.content.Context;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;

import com.shine.app.AppContext;

public class LocationUtil {
	private static final int FIVE_MINUTES = 1000 * 60 * 5;
	private Location currentBestLocation = null;
	private Context context;
	private AppContext appContext;
	private boolean gps_enabled = false;
	private boolean network_enabled = false;
	private LocationManager locationManager = null;
	private Location locationGPS = null;
	private Location locationNet = null;

	public LocationUtil() {
	}

	public LocationUtil(Context context, AppContext appContext) {
		this.context = context;
		this.appContext = appContext;
	}

	public Location getLastBestLocation() {
		if (currentBestLocation != null) {
			return currentBestLocation;
		}
		if (locationManager == null) {
			locationManager = (LocationManager) context
					.getSystemService(Context.LOCATION_SERVICE);
		}
		if (locationGPS == null) {
			locationGPS = locationManager
					.getLastKnownLocation(LocationManager.GPS_PROVIDER);
		}
		if (locationNet == null) {
			locationNet = locationManager
					.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
		}
		gps_enabled = locationManager
				.isProviderEnabled(LocationManager.GPS_PROVIDER);
		network_enabled = locationManager
				.isProviderEnabled(LocationManager.NETWORK_PROVIDER);

		if (!gps_enabled && !network_enabled) {
			currentBestLocation = null;
		}
		if (gps_enabled && locationGPS != null) {
			currentBestLocation = locationGPS;
		}
		if (network_enabled && locationNet != null) {
			currentBestLocation = locationNet;
		}
		if (gps_enabled && network_enabled) {
			long GPSLocationTime = 0;
			if (locationGPS != null) {
				GPSLocationTime = locationGPS.getTime();
			}
			long NetLocationTime = 0;
			if (locationNet != null) {
				NetLocationTime = locationNet.getTime();
			}
			if (GPSLocationTime > NetLocationTime) {
				currentBestLocation = locationGPS;
			} else {
				currentBestLocation = locationNet;
			}
		}
		if (currentBestLocation != null) {
			locationManager.requestLocationUpdates(
					currentBestLocation.getProvider(), 0, 0, locationListener);
		}
		return currentBestLocation;
	}

	/**
	 * This method modify the last know good location according to the
	 * arguments.
	 * 
	 * @param location
	 *            The possible new location.
	 */
	void makeUseOfNewLocation(Location location) {
		if (isBetterLocation(location, currentBestLocation)) {
			currentBestLocation = location;
		}
	}

	/**
	 * Determines whether one location reading is better than the current
	 * location fix
	 * 
	 * @param location
	 *            The new location that you want to evaluate
	 * @param currentBestLocation
	 *            The current location fix, to which you want to compare the new
	 *            one.
	 */
	protected boolean isBetterLocation(Location location,
			Location currentBestLocation) {
		if (currentBestLocation == null) {
			// A new location is always better than no location
			return true;
		}

		// Check whether the new location fix is newer or older
		long timeDelta = location.getTime() - currentBestLocation.getTime();
		boolean isSignificantlyNewer = timeDelta > FIVE_MINUTES;
		boolean isSignificantlyOlder = timeDelta < -FIVE_MINUTES;
		boolean isNewer = timeDelta > 0;

		// If it's been more than two minutes since the current location, use
		// the new location,
		// because the user has likely moved.
		if (isSignificantlyNewer) {
			return true;
			// If the new location is more than two minutes older, it must be
			// worse.
		} else if (isSignificantlyOlder) {
			return false;
		}

		// Check whether the new location fix is more or less accurate
		int accuracyDelta = (int) (location.getAccuracy() - currentBestLocation
				.getAccuracy());
		boolean isLessAccurate = accuracyDelta > 0;
		boolean isMoreAccurate = accuracyDelta < 0;
		boolean isSignificantlyLessAccurate = accuracyDelta > 200;

		// Check if the old and new location are from the same provider
		boolean isFromSameProvider = isSameProvider(location.getProvider(),
				currentBestLocation.getProvider());

		// Determine location quality using a combination of timeliness and
		// accuracy
		if (isMoreAccurate) {
			return true;
		} else if (isNewer && !isLessAccurate) {
			return true;
		} else if (isNewer && !isSignificantlyLessAccurate
				&& isFromSameProvider) {
			return true;
		}
		return false;
	}

	/** Checks whether two providers are the same */
	private boolean isSameProvider(String provider1, String provider2) {
		if (provider1 == null) {
			return provider2 == null;
		}
		return provider1.equals(provider2);
	}

	public LocationListener locationListener = new LocationListener() {
		public void onLocationChanged(Location location) {
			if (location != null) {
				makeUseOfNewLocation(location);
				if (currentBestLocation == null) {
					currentBestLocation = location;
				}

				if (currentBestLocation != null) {
					appContext.setLatitude(currentBestLocation.getLatitude());
					appContext.setLongitude(currentBestLocation.getLongitude());
				}
			}
		}

		public void onProviderDisabled(String provider) {
		}

		public void onProviderEnabled(String provider) {
		}

		public void onStatusChanged(String provider, int status, Bundle extras) {
		}
	};
}
